package com.sftz.modules.minapp.user.service;

import java.sql.Timestamp;
import java.util.Map;

import javax.servlet.http.HttpSession;

import me.chanjar.weixin.common.error.WxErrorException;

import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.SqlManager;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;

import com.sftz.assets.entities.ThirdPartyUserEntity;
import com.sftz.assets.enums.PlatFollowStatusEnum;
import com.sftz.assets.enums.PlatformEnum;
import com.sftz.framework.mvc.access.AccessConfig;
import com.sftz.framework.mvc.access.sign.MD5;
import com.sftz.framework.rersult.MobileResult;
import com.sftz.framework.res.entities.SUserEntity;
import com.sftz.framework.res.enums.UserStatusEnum;
import com.sftz.framework.res.enums.UserTypeEnum;
import com.sftz.framework.vendors.minapp.WxMaServiceManager;
import com.sftz.modules.common.dto.WxMinappTelDto;
import com.sftz.modules.common.dto.WxMinappUserDto;
import com.sftz.modules.common.form.UserBandTelForm;
import com.sftz.modules.common.service.WxMinappUserService;
import com.sftz.modules.minapp.user.cache.RedissionUserCache;
import com.sftz.modules.minapp.user.cache.WxSessionKeyCache;
import com.sftz.modules.minapp.user.dto.WeappUserTokenDto;
import com.sftz.modules.minapp.user.form.CaptchaForm;
import com.sftz.modules.minapp.user.form.LoginTokenForm;
import com.sftz.modules.minapp.user.form.WxMaUserForm;
import com.uxuexi.core.common.util.BeanUtil;
import com.uxuexi.core.common.util.DateTimeUtil;
import com.uxuexi.core.common.util.Util;
import com.uxuexi.core.db.dao.IDbDao;
import com.uxuexi.core.db.util.DbSqlUtil;
import com.uxuexi.core.redis.RedisDao;
import com.we.business.sms.SMSService;
import com.we.business.sms.enums.SmsType;
import com.we.business.sms.impl.AliYunSMSServiceImpl;

/**
 * 微信小程序用户接口
 */
@IocBean
public class WxMaUserViewService {

	@Inject
	protected IDbDao dbDao;

	@Inject
	private RedisDao redisDao;

	@Inject
	protected SqlManager sqlManager;

	private static final Log log = Logs.get();

	@Inject
	private WxMinappUserService wxMinappUserService;

	/**
	 * 使用code换取openid和sessionKey
	 * <p>
	 * 必须保证获取到最新的可用token，旧的token应该移除，同时移除缓存中旧token对应的用户信息
	 */
	public Object getSessionKey(final LoginTokenForm form, HttpSession session) {
		log.debug("请求获取token");
		try {
			String code = form.getCode();
			String oldToken = form.getToken();

			if (!Util.isEmpty(oldToken)) {
				//移除旧的token
				String cacheSk = WxSessionKeyCache.getSessionKey(oldToken);
				if (!Util.isEmpty(cacheSk)) {
					log.debug("移除旧的token以及userInfo");
					WxSessionKeyCache.remove(oldToken);
					RedissionUserCache.remove(cacheSk);
				}
			}

			WxMaService wxService = WxMaServiceManager.getMaService();
			WxMaJscode2SessionResult wxsession = wxService.getUserService().getSessionInfo(code);

			//存储sessionKey
			String newToken = session.getId();
			String sessionKey = wxsession.getSessionKey();
			log.debug("新的token:" + newToken + "-sessionKey:" + sessionKey);

			WxSessionKeyCache.putSessionKey(newToken, sessionKey);

			WeappUserTokenDto dto = new WeappUserTokenDto();
			BeanUtil.copyProperties(wxsession, dto);
			dto.setToken(newToken);

			return MobileResult.success("success", dto);
		} catch (WxErrorException e) {
			log.error(e.getMessage(), e);
			return MobileResult.error(e.getMessage(), null);
		}
	}

	/**
	 * 登录,获取用户信息
	 * <P>
	 * 先用token换取sessionKey,再用sessionKey获取用户。
	 * 注意:接口每次返回的用户信息必然是最新的
	 */
	public Object login(final WxMaUserForm form) {
		String token = form.getToken();
		log.debug("登录获取用户信息,token:" + token);
		String sessionKey = WxSessionKeyCache.getSessionKey(token);
		if (Util.isEmpty(sessionKey)) {
			return MobileResult.error("用户未授权登录", null);
		}

		// 用户信息校验
		String rawData = form.getRawData();
		String signature = form.getSignature();

		WxMaService wxService = WxMaServiceManager.getMaService();
		if (!wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
			return MobileResult.error("user check failed", null);
		}

		// 解密用户信息
		String encryptedData = form.getEncryptedData();
		String iv = form.getIv();
		WxMaUserInfo wxUser = wxService.getUserService().getUserInfo(sessionKey, encryptedData, iv);

		String unionId = wxUser.getUnionId();
		if (Util.isEmpty(unionId)) {
			return MobileResult.error("unionId不能为空,请先绑定微信开放平台", null);
		}
		WxMinappUserDto user = wxMinappUserService.login(wxUser);

		//如果用户状态不是有效的，则返回提示信息，用户被禁用
		if (!Util.isEmpty(user)) {
			Integer status = user.getStatus();
			if (!Util.isEmpty(status) && UserStatusEnum.VALID.intKey() != status) {
				return MobileResult.error("该用户已被禁用", null);
			}
		}

		//缓存用户
		RedissionUserCache.cacheUser(token, user);
		return MobileResult.success("success", user);
	}

	/**
	 * 检查手机号是否存在
	 */
	public Map<String, Object> checkTel(final String tel) {
		SUserEntity suser = dbDao.fetch(SUserEntity.class, Cnd.where("tel", "=", tel));
		if (Util.isEmpty(suser)) {
			return MobileResult.success("SUCCESS", false);
		} else {
			return MobileResult.success("SUCCESS", true);
		}
	}

	/**
	 * 微信用户绑定手机号接口
	 */
	@Aop("txDb")
	public Map<String, Object> bandTel(UserBandTelForm form) {

		String unionId = form.getUnionId();
		String avatar = form.getAvatarUrl();
		String nickName = form.getNickName();
		String tel = form.getTel();
		String password = form.getPassword();

		log.debug("unionId:" + unionId);
		log.debug("avatar:" + avatar);
		log.debug("nickName:" + nickName);
		log.debug("tel:" + tel);
		log.debug("password:" + password);

		SMSService smsService = new AliYunSMSServiceImpl(redisDao);
		String captchaInRedis = smsService.getCaptcha(SmsType.ALIYUN_SMS_CAPTCHA, tel);
		if (Util.isEmpty(captchaInRedis) || !captchaInRedis.equals(form.getCaptcha())) {
			return MobileResult.error("验证码错误", null);
		}

		ThirdPartyUserEntity tu = dbDao.fetch(ThirdPartyUserEntity.class,
				Cnd.where("unionId", "=", unionId).and("platform", "=", PlatformEnum.WEIXIN.intKey()));
		Timestamp now = DateTimeUtil.nowDateTime();
		Integer userId = form.getId();
		Integer userStatus = null;
		//第三方表里没有相关用户
		if (Util.isEmpty(tu)) {
			log.info("微信用户unionId:" + unionId + " 绑定手机号TEL:" + tel);

			//先查询用户表有没有该手机号
			SUserEntity suser = dbDao.fetch(SUserEntity.class, Cnd.where("tel", "=", tel));

			//用户表里没有相关手机号也没有第三方用户
			if (Util.isEmpty(suser)) {
				if (Util.isEmpty(password)) {
					return MobileResult.error("登录密码不能为空", null);
				}

				SUserEntity u = new SUserEntity();
				//激活
				userStatus = UserStatusEnum.VALID.intKey();

				String ciphertext = MD5.sign(password, AccessConfig.password_secret, AccessConfig.INPUT_CHARSET);
				u.setAvatar(avatar);
				u.setCreateTime(now);
				u.setNickName(nickName);
				u.setUserType(UserTypeEnum.THIRDPARTY.intKey()); //第三方用户
				u.setStatus(userStatus);
				u.setTel(tel);
				u.setPassword(ciphertext);
				u.setLastLoginTime(now);
				u = dbDao.insert(u);
				userId = u.getId();

				tu = new ThirdPartyUserEntity();
				tu.setUserId(u.getId());
				tu.setUnionId(unionId);
				tu.setPlatform(PlatformEnum.WEIXIN.intKey());
				tu.setCreateTime(DateTimeUtil.nowDateTime());
				tu.setFollowStatus(PlatFollowStatusEnum.UNFOLLOW.intKey());
				dbDao.insert(tu);

			} else {
				userId = suser.getId();
				userStatus = suser.getStatus();

				//用户表手机号已存在,查询该手机号有没有被绑定微信
				Sql bandSql = Sqls.create(sqlManager.get("minapp_user_isBanded"));
				bandSql.setParam("tel", tel);
				bandSql.setParam("platform", PlatformEnum.WEIXIN.intKey());

				WxMinappTelDto phonecount = DbSqlUtil.fetchEntity(dbDao, WxMinappTelDto.class, bandSql);

				if (Util.isEmpty(phonecount)) {
					//未绑定

					//更新昵称,头像,上次登录时间
					dbDao.update(SUserEntity.class,
							Chain.make("nickName", nickName).add("avatar", avatar).add("lastLoginTime", now),
							Cnd.where("id", "=", userId));

					tu = new ThirdPartyUserEntity();
					tu.setUserId(userId);
					tu.setUnionId(unionId);
					tu.setPlatform(PlatformEnum.WEIXIN.intKey());
					tu.setCreateTime(now);
					tu.setFollowStatus(PlatFollowStatusEnum.UNFOLLOW.intKey());
					dbDao.insert(tu);
				} else {
					//已绑定微信
					log.error("绑定失败!该用户已经绑定了微信账号,tel:" + tel);
					return MobileResult.error("绑定失败!该用户之前已经绑定了微信账号", null);
				}

			}
		} else {
			//更新登录时间
			log.info("=====================第三方表存在该微信用户===========================");
			userId = tu.getUserId();
			int count = dbDao.update(SUserEntity.class, Chain.make("lastLoginTime", now), Cnd.where("id", "=", userId));
			form.setLastLoginTime(now);
			if (count < 1) {
				log.error("数据错误,微信用户不存在对应的系统用户,unionId:" + unionId);
				return MobileResult.error("数据错误!", null);
			}
		}

		WxMinappUserDto re = new WxMinappUserDto();
		log.debug("用户id:" + userId);
		log.debug("上次登录时间:" + now);
		log.debug("用户状态:" + userStatus);

		form.setId(userId);
		form.setLastLoginTime(now);
		form.setStatus(userStatus);
		form.setBandTel(true);
		BeanUtil.copyProperties(form, re);
		//王宏伟：获取平台用户头像和昵称
		SUserEntity SUserEntity = dbDao.fetch(SUserEntity.class, Cnd.where("id", "=", userId));
		if (!Util.isEmpty(SUserEntity)) {
			re.setAvatar(SUserEntity.getAvatar());
			re.setNickName(SUserEntity.getNickName());
		}
		return MobileResult.success("SUCCESS", re);
	}

	/**
	 * 发送手机验证码
	 */
	public Map<String, Object> sendCaptcha(final String tel) {
		if (Util.isEmpty(tel)) {
			return MobileResult.error("手机号不能为空", null);
		}

		try {
			SMSService smsService = new AliYunSMSServiceImpl(redisDao);
			String captcha = smsService.sendCaptcha(SmsType.ALIYUN_SMS_CAPTCHA, tel);
			if (Util.isEmpty(captcha)) {
				return MobileResult.error("发送失败!", null);
			} else {
				return MobileResult.success("发送成功!", null);
			}
		} catch (Exception e) {
			e.printStackTrace();
			return MobileResult.error(e.getMessage(), null);
		}
	}

	/**
	 * 检查验证码是否正确
	 */
	public Map<String, Object> checkCaptcha(final CaptchaForm form) {
		SMSService smsService = new AliYunSMSServiceImpl(redisDao);
		String captchaInRedis = smsService.getCaptcha(SmsType.ALIYUN_SMS_CAPTCHA, form.getTel());
		if (!Util.isEmpty(captchaInRedis) && captchaInRedis.equals(form.getCaptcha())) {
			return MobileResult.success("验证码正确", null);
		} else {
			return MobileResult.error("验证码错误", null);
		}
	}

}
